import { Server, WebSocket } from 'ws'
import http from 'http'
import Koa from 'koa'
import { CommunicationChannelKeys, CustomWebSocket, RouteCallback, WsUrl } from "./type"

export default class MyWebSocket {
    private wss: Server<typeof WebSocket> | null = null
    private app: Koa | null = null
    private communicationChannelsArray = new Map<string, Record<string, any>>()
    private routes = new Map<WsUrl, RouteCallback>()
    constructor(wss: Server<typeof WebSocket, typeof http.IncomingMessage>, app: Koa) {
        this.wss = wss
        this.app = app
        this.init()
    }
    public init(keys = [CommunicationChannelKeys.Main]) {
        // 评论绑定事件
        keys.forEach((key) => this.addCommunicationChannel(key))
        this.connection()
        this.listening()
        this.close()
        this.error()
    }
    // 添加通信通道
    public addCommunicationChannel(key: CommunicationChannelKeys) {
        if (this.communicationChannelsArray.get(key)) {
            throw new Error('通信通道已经存在，请排查问题')
        } else {
            this.communicationChannelsArray.set(key, {})
        }
    }
    // 连接事件 const ws  = new WebSocket('ws://localhost:8001/main?token=testToken123')
    // ws.onmessage = (msg) => console.log(msg)
    // ws.send(JSON.stringify({ url: '/test1', data: {msg: 'message中文'} }))
    private connection() {
        this.wss?.on('connection', (ws: CustomWebSocket, req) => {
            const { url } = req // url 的值是 /$role/$uniId
            const urlParams = parseUrl(url)
            console.log('urlParams', urlParams)
            const communicationChannels = urlParams.communicationChannels
            const token = urlParams.queryParams.token
            if (!token) {
                // TODO:后续改成对象，要有code等结构
                ws.send('未携带token')
                return ws.close() //
            }
            const id = testVerify(urlParams.queryParams.token)
            // ws.user = 
            console.log("id", id)
            // 建立连接

            ws.on('message', (msg: string, isBinary: boolean) => {
                try {
                    const params = JSON.parse(msg.toString()) as { url: WsUrl; data: Record<string, any> }
                    const callback = this.routes.get(params.url)
                    if (callback) {
                        callback(ws, params.data)
                    } else {
                        console.warn(`未找到对应的路由:${params.url}`)
                    }

                } catch (error) {
                    throw error
                }
            })
            ws.on('open', () => {
                // 连接成功后的操作
                console.log('---open---')
            });
            ws.on('error', () => {
                // 处理错误
                console.log('---error---')
            });
            ws.on('close', () => {
                // 处理连接关闭
                console.log('---close---')
            });
        })
    }
    private listening() {
        this.wss?.on('listening', () => {
            console.log('-----server listening-----')
        })
    }
    private close() {
        this.wss?.on('close', () => {
            console.log('-----server close-----')
        })
    }
    private error() {
        this.wss?.on('error', (err: Error) => {
            console.log('-----server error-----', err)
        })
    }
    // 注册路由
    addRoutes(routes: Array<{ url: WsUrl; callback: RouteCallback }>) {
        routes.forEach(({ url, callback }) => {
            if (this.routes.has(url)) throw new Error(`路由已存在: ${url}`)
            this.routes.set(url, callback)
        })
    }
}


function parseUrl(url = '') {
    const urlParts = url.split('?');
    const path = urlParts[0];
    const queryParams = new URLSearchParams(urlParts[1]);
    const pathParts = path.split('/');
    const paramsObject: Record<string, string> = {};
    for (const [key, value] of queryParams.entries()) {
        paramsObject[key] = value;
    }
    return {
        communicationChannels: pathParts[1],
        queryParams: paramsObject
    };
}

function testVerify(token: string) {
    console.log('testVerify', token)
    return `end-${token}`
}